home *** CD-ROM | disk | FTP | other *** search
/ Aminet 35 / Aminet 35 (2000)(Schatztruhe)[!][Feb 2000].iso / Aminet / util / arc / CheckX.lha / CheckX / sources / CheckX.c next >
Encoding:
C/C++ Source or Header  |  1999-12-06  |  46.0 KB  |  1,590 lines

  1. #define NAME         "CheckX"
  2. #define REVISION     "68"
  3. #define DISTRIBUTION "(Freeware) "
  4.  
  5. /*
  6. This program scans for crunched, linked files and archived files. It
  7. decrunches them and saves the result files to another directory-tree.
  8. The scanning routines are recursiv and thus check really all stuff.
  9.  
  10. The program must be compiled and linked without startup-code. You can set
  11. the pure file protection bit and make it resident, because it is multi-
  12. reentrant (no global variables, except library bases).
  13.  
  14. Disk archives are handled this way:
  15. They are unarchived to RD0: in depth1, to RD1: in depth2 (when archive is
  16. in RD0:) and to RD2: in depth3, ....
  17.  
  18. NOTE: accessing RD0:, RD1 or RD2: during this time may produce errors.
  19. This includes starting CheckX twice, when scanning disk archives. For high
  20. density archives the archive names are RH1:, RH2:, ...
  21.  
  22. Crypted archives are not supported yet (e.g. asking for password).
  23. */
  24.  
  25. /* Programmheader
  26.  
  27.     Name:        CheckX
  28.     Author:        SDI
  29.     Distribution:    Freeware
  30.     Description:    scans and decrunches crunched files with xfd
  31.     Compileropts:    -
  32.     Linkeropts:    -l xpkmaster xadmaster amiga -gsi
  33.  
  34.  1.0   14.12.96 : first Version
  35.  1.1   28.12.96 : moved PassRequest into xpkmaster.library
  36.  1.2   12.02.97 : now also decrunches Exe-Files
  37.  1.3   15.06.97 : added length output as test
  38.  1.4   21.11.97 : renamed from Decrunch, got really new program
  39.  1.5   22.11.97 : bug-fixes
  40.  1.6   29.11.97 : added unarchiving feature
  41.  1.7   30.11.97 : bug-fixes
  42.  1.8   06.12.97 : xpkmaster.library now only required with ASKPWD option
  43.  1.9   07.12.97 : Added archive copy for weird archive names, better error
  44.     codes
  45.  1.10  08.12.97 : fixed error codes a bit
  46.  1.11  11.12.97 : disabled DOS requests, added Zip-Archives, added TaskID
  47.     to temporary filenames
  48.  1.12  12.12.97 : added Arc, ZOO and LhASFX archives
  49.  1.13  13.12.97 : fixed Arc recognition
  50.  1.14  19.12.97 : deletes copied arc before scan
  51.  1.15  22.12.97 : crunched archives are unarchived correctly now
  52.  1.16  02.01.98 : opens dos.library itself, no startup-code required
  53.  1.17  23.01.98 : added disk crunchers
  54.  1.18  24.01.98 : some fixes
  55.  1.19  01.02.98 : little bug-fix in argument-option use
  56.  1.20  06.02.98 : better error output, added automount
  57.  1.21  08.02.98 : little bug-fix
  58.  1.22  10.02.98 : fixed archive copy conditions, added PRINTALL
  59.  1.23  12.02.98 : fixed help text, bug fixes with unlinking and FreeMem
  60.  1.24  13.02.98 : added unstripping
  61.  1.25  04.03.98 : added PRINTEXEC
  62.  1.26  13.03.98 : added high density DMS support
  63.  1.27  19.03.98 : added LOUD keyword
  64.  1.28  23.03.98 : RDx no longer depends on archive depth, but on dddepth
  65.  1.29  10.04.98 : bug fixes
  66.  1.30  26.04.98 : bug fixes
  67.  1.31  09.05.98 : now uses no longer adress 4 for SysBase
  68.  1.32  31.05.98 : better output
  69.  1.33  04.06.98 : added HEADER addition for address files
  70.  1.34  08.08.98 : bug fix with SAVE
  71.  1.35  24.09.98 : added xvs.library virus checks
  72.  1.36  18.10.98 : xvs is opened global and only once
  73.  1.37  30.10.98 : renamed from CheckXFD
  74.  1.38  11.11.98 : fixed format drive bug using a delay and an error report
  75.  1.39  14.11.98 : format error with AUTOMOUNT removed
  76.  1.40  16.11.98 : removed HEADER addition stuff
  77.  1.41  18.11.98 : better RDx: access and mount
  78.  1.42  23.11.98 : fixed bug with hunk stripping
  79.  1.43  29.12.98 : now prints an error, when virus detection is turned off,
  80.     added time calculation and output
  81.  1.44  31.12.98 : little bug fix
  82.  1.45  06.02.99 : bug fixes, added xadmaster.library stuff, removed LOUD
  83.     and internal DMS call
  84.  1.46  09.02.99 : removed internal LZX call
  85.  1.47  11.02.99 : now uses assembler startcode allocating a bigger stack
  86.  1.48  14.02.99 : bug-fixes for nocylinder archivers (PackDev)
  87.  1.49  16.02.99 : fixed strip option (don't know, where the error was :-)
  88.  1.50  21.02.99 : removed internal Zoom call and disk-archiver stuff
  89.  1.51  22.02.99 : fixed archiver call for remaining non-XAD archivers, added
  90.     empty file check
  91.  1.52  23.02.99 : fixed StartCode return value
  92.  1.53  24.02.99 : forgot empty check for archived files
  93.  1.54  08.03.99 : old archiver calling did not work, when file was XAD
  94.     unarchived
  95.  1.55  26.03.99 : prints error, when logfile cannot be created
  96.  1.56  30.03.99 : added bootblock scanning for unarchived disks
  97.  1.57  16.05.99 : bug fix with unlinked file save
  98.  1.58  17.07.99 : removed internal LhA Support
  99.  1.59  30.07.99 : bug fix with file name prints
  100.  1.60  03.08.99 : added DEBUG option
  101.  1.61  05.08.99 : added XVS SelfTest and MemoryTest
  102.  1.62  19.08.99 : added error summary, again fixed name problem
  103.  1.63  14.09.99 : solved big memory loss problem (did not free xadArchiveInfo),
  104.     added logfile comment
  105.  1.64  17.10.99 : removed external archiver calls, added QUIET
  106.  1.65  24.11.99 : now sets nice return values
  107.  1.66  26.11.99 : tries reading again before giving read error
  108.  1.67  03.12.99 : bug fix in name printing
  109.  1.68  04.12.99 : tries again opening files.
  110. */
  111.  
  112. #include <proto/exec.h>
  113. #include <proto/dos.h>
  114. #include <proto/xfdmaster.h>
  115. #include <proto/xadmaster.h>
  116. #include <proto/xpkmaster.h>
  117. #include <proto/intuition.h>
  118. #include <proto/xvs.h>
  119. #include <proto/utility.h>
  120. #include <libraries/xfdmaster.h>
  121. #include <dos/dostags.h>
  122. #include <dos/doshunks.h>
  123. #include <dos/filehandler.h>
  124. #include <exec/memory.h>
  125. #include "SDI_defines.h" /* make version string */
  126.  
  127. #define SDI_TO_ANSI
  128. #include "SDI_ASM_STD_protos.h"
  129.  
  130. #define PARAM   "FROM,LOG,SAVE/K,ALL/S,ASKPWD/S,AUTOMOUNT/S,PRINTALL/S," \
  131.         "PRINTEXEC/S,"                          \
  132.         "NODECRUNCH/S,NOUNLINK/S,NOUNARCHIVE/S,NOUNTRACK/S,"     \
  133.         "NOTRACKCUT/S,NOSTRIP/S,NOVIRUS/S,DEBUG/S,QUIET/S"
  134.  
  135. void RawPutChar(ULONG c);
  136.  
  137. #ifdef __SASC
  138.   #pragma libcall SysBase RawPutChar 204 001
  139. #elif defined(__GNUC__)
  140.   #define RawPutChar(c) LP1NR(204, RawPutChar, ULONG, c, d0, , SysBase)
  141. #else
  142.   #pragma amicall(SysBase,0x204,RawPutChar(d0))
  143. #endif
  144.  
  145. void KPutC(ULONG c)
  146. {
  147.   RawPutChar(c);
  148. }
  149.  
  150. void KPrintf(STRPTR fmt, ...)
  151. {
  152.   RawDoFmt(fmt, &fmt + 1, (void (*)()) KPutC, 0);
  153. }
  154.  
  155. #ifdef __SASC
  156.   #define XpkBase    xpkbase
  157.   #define ASSIGN_XPK
  158.   #define IntuitionBase    intuitionbase
  159.   #define ASSIGN_INT
  160.   #define UtilityBase    utilitybase
  161.   #define ASSIGN_UTIL
  162. #else
  163.   struct Library *    XpkBase        = 0;
  164.   struct IntuitionBase *IntuitionBase    = 0;
  165.   struct Utilitybase *  UtilityBase     = 0;
  166.   #define ASSIGN_XPK    XpkBase = xpkbase;
  167.   #define ASSIGN_INT    IntuitionBase = intuitionbase;
  168.   #define ASSIGN_UTIL    UtilityBase = utilitybase;
  169. #endif
  170. struct xfdMasterBase *    xfdMasterBase    = 0;
  171. struct DosLibrary *    DOSBase        = 0;
  172. struct ExecBase *    SysBase        = 0;
  173. struct xvsBase *    xvsBase        = 0;
  174. struct xadMasterBase *    xadMasterBase    = 0;
  175.  
  176. struct Args {
  177.   STRPTR from;
  178.   STRPTR log;
  179.   STRPTR save;
  180.   ULONG  all;
  181.   ULONG  askpwd;
  182.   ULONG  automount;
  183.   ULONG  printall;
  184.   ULONG  printexec;
  185.   ULONG  nodecrunch;
  186.   ULONG  nounlink;
  187.   ULONG  nounarchive;
  188.   ULONG  nountrack;
  189.   ULONG  notrackcut;
  190.   ULONG  nostrip;
  191.   ULONG  novirus;
  192.   ULONG  debug;
  193.   ULONG     quiet;
  194. };
  195.  
  196. struct CrunchMemList {
  197.   struct CrunchMemList * cml_Next;
  198.   APTR             cml_MemoryRegion;
  199.   ULONG             cml_MemorySize;
  200. };
  201.  
  202. #define CHECKXFLAG_SAVE            (1<< 0)
  203. #define CHECKXFLAG_ALL            (1<< 1)
  204. #define CHECKXFLAG_ASKPWD        (1<< 2)
  205. #define CHECKXFLAG_AUTOMOUNT        (1<< 3)
  206. #define CHECKXFLAG_PRINTALL        (1<< 4)
  207. #define CHECKXFLAG_PRINTEXEC        (1<< 5)
  208. #define CHECKXFLAG_NODECRUNCH        (1<< 6)
  209. #define CHECKXFLAG_NOUNLINK        (1<< 7)
  210. #define CHECKXFLAG_NOUNARCHIVE        (1<< 8)
  211. #define CHECKXFLAG_NOUNTRACK        (1<< 9)
  212. #define CHECKXFLAG_NOTRACKCUT        (1<<10)
  213. #define CHECKXFLAG_NOSTRIP        (1<<11)
  214. #define CHECKXFLAG_DEBUG        (1<<12)
  215. #define CHECKXFLAG_QUIET        (1<<13)
  216.  
  217. #define CHECKXFLAG_XVSLIB        (1<<15)
  218. #define CHECKXFLAG_XADLIB        (1<<16)
  219. #define CHECKXFLAG_STRIPNAME        (1<<17)
  220.  
  221. #define CHKXCALLFLAGS    (CHECKXFLAG_SAVE|CHECKXFLAG_ALL|        \
  222.              CHECKXFLAG_ASKPWD|CHECKXFLAG_AUTOMOUNT|    \
  223.              CHECKXFLAG_PRINTALL|CHECKXFLAG_PRINTEXEC|    \
  224.              CHECKXFLAG_NODECRUNCH|CHECKXFLAG_NOUNLINK|    \
  225.              CHECKXFLAG_NOUNARCHIVE|CHECKXFLAG_NOUNTRACK|    \
  226.              CHECKXFLAG_NOTRACKCUT|CHECKXFLAG_NOSTRIP|    \
  227.              CHECKXFLAG_DEBUG|CHECKXFLAG_QUIET|        \
  228.              CHECKXFLAG_XVSLIB|CHECKXFLAG_XADLIB|        \
  229.              CHECKXFLAG_STRIPNAME)
  230.  
  231. #define CHKXSAVEFLAGS    (CHECKXFLAG_LINKED|CHECKXFLAG_CRUNCHED|        \
  232.              CHECKXFLAG_STRIPPED)
  233.  
  234. #define CHECKXFLAG_NAMEPRINTED        (1<<20)
  235. #define CHECKXFLAG_CRUNCHED        (1<<21)
  236. #define CHECKXFLAG_LINKED        (1<<22)
  237. #define CHECKXFLAG_ADDRESS        (1<<23)
  238. #define CHECKXFLAG_NOFREEMEM        (1<<24)
  239. #define CHECKXFLAG_STRIPPED        (1<<25)
  240. #define CHECKXFLAG_HIGHDENSITY        (1<<26)
  241. #define CHECKXFLAG_FILEARCHIVED        (1<<27)
  242. #define CHECKXFLAG_DISKARCHIVED        (1<<28)
  243.  
  244. #define CHXWARN_OFFSET        30
  245. #define XADERR_OFFSET        0x100
  246. #define XFDERR_OFFSET        0x200
  247.  
  248. #define CHKXERR_NOMEMORY    1
  249. #define CHKXERR_EXAMINEERR    2
  250. #define CHKXERR_OPENERR        3
  251. #define CHKXERR_READ        4
  252. #define CHKXERR_SCANERR        5
  253. #define CHKXERR_BREAK        6
  254. #define CHKXERR_OPENDIR        7
  255. #define CHKXERR_NORAD        8
  256. #define CHKXERR_NODOS        9 /* not a dos disk */
  257. #define CHKXERR_RESOURCE    10
  258. #define CHKXERR_NOVIRUS        11
  259. #define CHKXERR_EMPTY        12
  260. #define CHKXERR_NOBOOTVIRUS    13
  261. #define CHKXERR_WRITE        14
  262.  
  263. #define CHKXWARN_NOVIRUS    31
  264. #define CHKXWARN_XVSSELFTEST    32
  265. #define    CHKXWARN_MEMVIRUS    33
  266.  
  267. struct FileData {
  268.   struct CrunchMemList * fd_MemList;
  269.   STRPTR         fd_Name;
  270.   ULONG           fd_LogFileFH;
  271.   ULONG           fd_SaveDirL;
  272.   ULONG             fd_Flags;
  273.   ULONG             fd_NumVirus;
  274.   ULONG             fd_CHKXErrors;
  275.   ULONG             fd_XFDErrors;
  276.   ULONG             fd_XADErrors;
  277.   ULONG             fd_CorruptedArchives;
  278.   BYTE           fd_RecurseDepth;
  279.   UBYTE           fd_LinkNum;
  280.   UBYTE             fd_ArchiveDepth;
  281.   UBYTE             fd_DDDepth;
  282.   UBYTE             fd_HDDepth;
  283. };
  284.  
  285. void SetLogComment(STRPTR);
  286. LONG DoDirectoryScan(STRPTR, STRPTR, struct FileData *);
  287. LONG DoFileOpen(struct FileData *);
  288. void DoMount(ULONG, ULONG);
  289. BPTR GetRad(struct FileData *, STRPTR);
  290. LONG DoGetVirus(struct FileData *, APTR, ULONG);
  291. LONG DoFileUnArchive(struct FileData *, APTR, ULONG);
  292. LONG DoFileUnLink(struct FileData *, APTR, ULONG);
  293. LONG DoFileUnCrunch(struct FileData *, APTR, ULONG);
  294. LONG DoFileStrip(struct FileData *, APTR, ULONG);
  295. void PrintCHKXFile(struct FileData *);
  296. void PrintCHKXErr(struct FileData *, LONG);
  297. void PrintCHKXTxt(struct FileData *, STRPTR, ...);
  298. LONG AddCrunchMemList(struct FileData *, APTR, ULONG);
  299. void FreeCrunchMemList(struct FileData *, APTR);
  300. LONG SaveUncrFile(struct FileData *, APTR, ULONG);
  301. ULONG OpenParentDir(struct FileData *);
  302. ULONG OpenNewDir(struct FileData *, STRPTR);
  303.  
  304. /* All memory regions must be in mem list. All unneeded memory must be freed
  305.    as fast as possible (after unlinking, decrunching), as well as the
  306.    MemoryList structure.
  307.    
  308.    The program has a loop like scan routine system, which is called for
  309.    every file:
  310.  
  311.    A) Scan files, directories and sub directories and call following for
  312.       every file:
  313.    1) Check for viruses.
  314.    2) Test if it is an archive. When yes decrunch and start with point A
  315.       (disk archives) or start for every file with point 1 (file archives).
  316.    3) Test if file is linked. When yes unlink and call point 1 for both
  317.       parts.
  318.    4) Test if file is crunched. When yes, decrunch and start again with
  319.       point 1.
  320.    5) Try stripping useless stuff. When successful start with point 1 again.
  321.    6) Possibly save file (with SAVE option) or end loop here.
  322. */
  323.  
  324. /* main routine, do argument parsing */
  325. LONG start(void)
  326. {
  327.   LONG error = RETURN_FAIL;
  328.   struct DosLibrary *dosbase;
  329.   struct Process *task;
  330.  
  331.   SysBase = (*((struct ExecBase **) 4));
  332.  
  333.   /* test for WB and reply startup-message */
  334.   if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  335.   {
  336.     WaitPort(&task->pr_MsgPort);
  337.     Forbid();
  338.     ReplyMsg(GetMsg(&task->pr_MsgPort));
  339.     return RETURN_FAIL;
  340.   }
  341.  
  342.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  343.   {
  344.     struct xfdMasterBase *xfdmasterbase;
  345.  
  346.     DOSBase = dosbase;
  347.  
  348.     if((xfdmasterbase = (struct xfdMasterBase *)
  349.     OpenLibrary("xfdmaster.library", 37)))
  350.     {
  351.       struct Args Args;
  352.       struct RDArgs *rda;
  353.  
  354.       xfdMasterBase = xfdmasterbase;
  355.  
  356.       memset(&Args, 0, sizeof(struct Args));
  357.  
  358.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  359.       {
  360.         rda->RDA_ExtHelp =
  361.         "FROM        source file or directory - may contain patterns\n"
  362.         "LOG         log file name\n"
  363.         "SAVE        directory, where decrunched files are saved\n"
  364.         "ALL         scan deep into directories\n"
  365.         "ASKPWD      ask for password when needed (needs xpkmaster.library)\n"
  366.     "PRINTALL    print all filenames\n"
  367.         "PRINTEXEC   print names of all executable files\n"
  368.     "AUTOMOUNT   automatically mount RDx: device when needed\n"
  369.         "NODECRUNCH  do not decrunch files with xfdmaster\n"
  370.         "NOUNLINK    do not unlink files with xfdmaster\n"
  371.         "NOUNARCHIVE do not call archiver for unarchiving file archives\n"
  372.         "NOUNTRACK   do not call archiver for unarchiving track archives\n"
  373.         "NOTRACKCUT  do not call archiver for partially track archives\n"
  374.         "NOSTRIP     do not strip useless hunks\n"
  375.         "NOVIRUS     do not scan with xvs.library for viruses\n"
  376.         "DEBUG       also output texts to serial debug engine\n"
  377.         "QUIET       do not output texts to console\n";
  378.  
  379.         if(ReadArgs(PARAM, (LONG *) &Args, rda))
  380.         {
  381.           ULONG flags = 0, log = 0;
  382.           struct xvsBase *xvsbase = 0;
  383.           struct xadMasterBase *xadmasterbase = 0;
  384.  
  385.           if(!Args.from)    Args.from = "#?";
  386.           if(Args.all)        flags |= CHECKXFLAG_ALL;
  387.           if(Args.save)        flags |= CHECKXFLAG_SAVE;
  388.           if(Args.askpwd)    flags |= CHECKXFLAG_ASKPWD;
  389.           if(Args.automount)    flags |= CHECKXFLAG_AUTOMOUNT;
  390.       if(Args.printall)    flags |= CHECKXFLAG_PRINTALL;
  391.       if(Args.printexec)    flags |= CHECKXFLAG_PRINTEXEC;
  392.           if(Args.nodecrunch)    flags |= CHECKXFLAG_NODECRUNCH;
  393.           if(Args.nounlink)     flags |= CHECKXFLAG_NOUNLINK;
  394.           if(Args.nounarchive)    flags |= CHECKXFLAG_NOUNARCHIVE;
  395.           if(Args.nountrack)    flags |= CHECKXFLAG_NOUNTRACK;
  396.           if(Args.notrackcut)    flags |= CHECKXFLAG_NOTRACKCUT;
  397.           if(Args.nostrip)    flags |= CHECKXFLAG_NOSTRIP;
  398.           if(Args.debug)    flags |= CHECKXFLAG_DEBUG;
  399.           if(Args.quiet)    flags |= CHECKXFLAG_QUIET;
  400.  
  401.           if(!Args.novirus)
  402.           {
  403.             if((xvsbase = (struct xvsBase *) OpenLibrary("xvs.library", 33)))
  404.             {
  405.               flags |= CHECKXFLAG_XVSLIB;
  406.               xvsBase = xvsbase;
  407.             }
  408.       }
  409.       if(!Args.nounarchive || !Args.nountrack)
  410.       {
  411.         if((xadmasterbase = (struct xadMasterBase *) OpenLibrary("xadmaster.library", 1)))
  412.         {
  413.           flags |= CHECKXFLAG_XADLIB;
  414.           xadMasterBase = xadmasterbase;
  415.         }
  416.       }
  417.  
  418.           if(!Args.log || (log = Open(Args.log, MODE_READWRITE)))
  419.           {
  420.         struct FileData fd;
  421.         APTR win;
  422.         ULONG s1 = 0, s2 = 0, msecs;
  423.         struct IntuitionBase *intuitionbase;
  424.  
  425.         win = task->pr_WindowPtr;
  426.         task->pr_WindowPtr = (APTR) -1;
  427.         /* prevent dos requests */
  428.  
  429.         if(log)
  430.         {
  431.           SetFileSize(log, 0, OFFSET_BEGINNING);
  432.           SetProtection(Args.log, FIBF_EXECUTE);
  433.           SetLogComment(Args.log);
  434.         }
  435.  
  436.         memset(&fd, 0, sizeof(struct FileData));
  437.             fd.fd_Flags = flags | CHECKXFLAG_NAMEPRINTED; /* for possible warnings display */
  438.             fd.fd_LogFileFH = log;
  439.  
  440.         if(!xvsbase)
  441.           PrintCHKXErr(&fd, CHKXWARN_NOVIRUS);
  442.         else
  443.         {
  444.               struct xvsMemoryInfo *mi;
  445.  
  446.           if(!xvsSelfTest())
  447.             PrintCHKXErr(&fd, CHKXWARN_XVSSELFTEST);
  448.  
  449.                 if((mi = (struct xvsMemoryInfo *) xvsAllocObject(XVSOBJ_MEMORYINFO)))
  450.                 { 
  451.                   if(xvsSurveyMemory(mi))
  452.               PrintCHKXErr(&fd, CHKXWARN_MEMVIRUS);
  453.  
  454.                   xvsFreeObject(mi);
  455.                 }
  456.         }
  457.  
  458.         if((intuitionbase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37)))
  459.         {
  460.           ASSIGN_INT
  461.           CurrentTime(&s1, &msecs);
  462.         }    
  463.  
  464.         ++fd.fd_RecurseDepth;
  465.         error = DoDirectoryScan(Args.from, Args.save, &fd) ? RETURN_FAIL : RETURN_OK;
  466.         --fd.fd_RecurseDepth;
  467.         fd.fd_Flags |= CHECKXFLAG_NAMEPRINTED; /* for result texts */
  468.  
  469.         task->pr_WindowPtr = win;
  470.  
  471.         if(intuitionbase)
  472.         {
  473.           CurrentTime(&s2, &msecs);
  474.           s2 -= s1;
  475.           s1 = s2 / 60;
  476.           s2 %= 60;
  477.           msecs = s1 / 60;
  478.           s1 %= 60;
  479.           PrintCHKXTxt(&fd, "\nTime needed for check: %2ld:%02ld:%02ld", msecs, s1, s2);
  480.           CloseLibrary((struct Library *) intuitionbase);
  481.         }
  482.         if(fd.fd_NumVirus)
  483.         {
  484.           PrintCHKXTxt(&fd, "The scan detected %ld virus%s.", fd.fd_NumVirus, fd.fd_NumVirus > 1 ? "es" : "");
  485.         }
  486.         if(fd.fd_CHKXErrors || fd.fd_XADErrors || fd.fd_XFDErrors || fd.fd_CorruptedArchives)
  487.           PrintCHKXTxt(&fd, "There were errors (CheckX/XFD/XAD/corrupted archives): %ld/%ld/%ld/%ld.",
  488.           fd.fd_CHKXErrors, fd.fd_XFDErrors, fd.fd_XADErrors, fd.fd_CorruptedArchives);
  489.         if(!error && (fd.fd_NumVirus || !xvsBase))
  490.         {
  491.           SetIoErr(0);
  492.           error = RETURN_WARN;
  493.         }
  494.  
  495.             if(log)
  496.               Close(log);
  497.           }
  498.           else if(Args.log && !Args.quiet)
  499.             Printf("Could not create logfile.\n");
  500.  
  501.       if(xvsbase)
  502.         CloseLibrary((struct Library *) xvsbase);
  503.       if(xadmasterbase)
  504.         CloseLibrary((struct Library *) xadmasterbase);
  505.           FreeArgs(rda);
  506.         }
  507.         FreeDosObject(DOS_RDARGS, rda);
  508.       }
  509.       CloseLibrary((struct Library *) xfdmasterbase);
  510.     }
  511.     CloseLibrary((struct Library *) dosbase);
  512.   }
  513.  
  514.   return error;
  515. }
  516.  
  517. void SetLogComment(STRPTR name)
  518. {
  519.   UBYTE com[30];
  520.   struct MsgPort *TimerMP;
  521.  
  522.   if((TimerMP = CreateMsgPort()))
  523.   {
  524.     struct timerequest *TimerIO;
  525.  
  526.     if((TimerIO = (struct timerequest *) CreateIORequest(TimerMP,
  527.     sizeof(struct timerequest))))
  528.     {
  529.       if(!OpenDevice("timer.device",UNIT_VBLANK,
  530.       (struct IORequest *)TimerIO,0))
  531.       {
  532.         struct UtilityBase *utilitybase;
  533.  
  534.         TimerIO->tr_node.io_Command = TR_GETSYSTIME;
  535.         DoIO((struct IORequest *) TimerIO);
  536.         if((utilitybase = (struct UtilityBase *) OpenLibrary("utility.library",37)))
  537.         {
  538.           struct ClockData dat;
  539.  
  540.       ASSIGN_UTIL
  541.           Amiga2Date(TimerIO->tr_time.tv_secs, &dat);
  542.           sprintf(com, "CheckX " VERSION "." REVISION " - %02ld.%02ld.%ld", dat.mday, dat.month, dat.year);
  543.       CloseLibrary((struct Library *) utilitybase);
  544.       SetComment(name, com);
  545.         }
  546.         CloseDevice((struct IORequest *) TimerIO);
  547.       }
  548.       DeleteIORequest(TimerIO);
  549.     }
  550.     DeleteMsgPort(TimerMP);
  551.   }
  552. }
  553.  
  554. /* This scans a directory and calls DoFileOpen for every file. It
  555.    automatically creates SAVE destination directories when necessary. */
  556. LONG DoDirectoryScan(STRPTR name, STRPTR sav, struct FileData *fd)
  557. {
  558.   struct AnchorPath *APath;
  559.   LONG error = CHKXERR_SCANERR;
  560.   ULONG retval;
  561.  
  562.   if(!(fd->fd_Flags & CHECKXFLAG_SAVE) || !sav ||
  563.   (fd->fd_SaveDirL = Lock(sav, SHARED_LOCK)))
  564.   {
  565.     if((APath = (struct AnchorPath *) AllocMem(sizeof(struct AnchorPath) +
  566.     512, MEMF_PUBLIC|MEMF_CLEAR)))
  567.     {
  568.       fd->fd_Name = APath->ap_Buf;
  569.       APath->ap_Strlen = 256;
  570.       for(retval = MatchFirst(name, APath); !retval;
  571.       retval = MatchNext(APath))
  572.       {
  573.         if(APath->ap_Flags & APF_DIDDIR)
  574.         {
  575.           OpenParentDir(fd);
  576.           APath->ap_Flags &= ~APF_DIDDIR; /* clear flag */
  577.         }
  578.         else if(APath->ap_Info.fib_DirEntryType > 0)
  579.         {
  580.           if(fd->fd_Flags & CHECKXFLAG_ALL)
  581.           {
  582.             OpenNewDir(fd, APath->ap_Info.fib_FileName);
  583.             APath->ap_Flags |= APF_DODIR;
  584.           }
  585.         }
  586.         else
  587.         {
  588.       fd->fd_Flags &= CHKXCALLFLAGS;
  589.           fd->fd_LinkNum = 0;
  590.           PrintCHKXErr(fd, DoFileOpen(fd));
  591.  
  592.           while(fd->fd_MemList)
  593.             FreeCrunchMemList(fd, fd->fd_MemList->cml_MemoryRegion);
  594.         }
  595.         if((fd->fd_Flags & CHECKXFLAG_SAVE) && !fd->fd_SaveDirL)
  596.         {
  597.           error = CHKXERR_OPENDIR; break;
  598.         }
  599.         if(CTRL_C)
  600.         {
  601.           error = CHKXERR_BREAK; break;
  602.         }
  603.       }
  604.       MatchEnd(APath);
  605.  
  606.       if(retval == ERROR_NO_MORE_ENTRIES)
  607.         error = 0;
  608.  
  609.       FreeMem(APath, sizeof(struct AnchorPath) + 512);
  610.     }
  611.     else
  612.       error = CHKXERR_NOMEMORY;
  613.  
  614.     if(sav && fd->fd_SaveDirL)
  615.       UnLock(fd->fd_SaveDirL);
  616.   }
  617.   else
  618.     error = CHKXERR_OPENDIR;
  619.  
  620.   return error;
  621. }
  622.  
  623. /* Open a file and call DoGetVirus to scan */
  624. LONG DoFileOpen(struct FileData *fd)
  625. {
  626.   struct FileInfoBlock *fib;
  627.   LONG ret = 0;
  628.  
  629.   if((fib = (struct FileInfoBlock *) AllocDosObject(DOS_FIB, 0)))
  630.   {
  631.     ULONG fh;
  632.  
  633.     if(fd->fd_ArchiveDepth) /* prevent scan errors */
  634.       SetProtection(fd->fd_Name, 0); /* set RWED bits */
  635.     if(!(fh = Open(fd->fd_Name, MODE_OLDFILE)))
  636.     {
  637.       Delay(TICKS_PER_SECOND);
  638.       fh = Open(fd->fd_Name, MODE_OLDFILE);
  639.     }
  640.  
  641.     if(fh)
  642.     {
  643.       if(ExamineFH(fh, fib))
  644.       {
  645.         APTR mem;
  646.  
  647.     if(!fib->fib_Size)
  648.           ret = CHKXERR_EMPTY;
  649.         else if((mem = AllocMem(fib->fib_Size, MEMF_ANY)))
  650.         {
  651.           if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
  652.           {
  653.             Delay(TICKS_PER_SECOND);
  654.             if(Read(fh, mem, fib->fib_Size) != fib->fib_Size)
  655.               ret = CHKXERR_READ;
  656.           }
  657.           
  658.           if(!ret && !(ret = AddCrunchMemList(fd, mem, fib->fib_Size)))
  659.           {
  660.             if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  661.             ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && fib->fib_Size > 4
  662.             && *((ULONG *)mem) == HUNK_HEADER))
  663.               PrintCHKXFile(fd);
  664.             ret = DoGetVirus(fd, mem, fib->fib_Size);
  665.           }
  666.         }
  667.         else
  668.           ret = CHKXERR_NOMEMORY;
  669.       }
  670.       else
  671.         ret = CHKXERR_EXAMINEERR;
  672.       Close(fh);
  673.     }
  674.     else
  675.       ret = CHKXERR_OPENERR;
  676.   
  677.     FreeDosObject(DOS_FIB, fib);
  678.   }
  679.   else
  680.     ret = CHKXERR_NOMEMORY;
  681.  
  682.   return ret;
  683. }
  684.  
  685. /* for SAVE option: open parent directory and try to delete the directory
  686.    we leave. This only succeeds, when the directory is empty. */
  687. ULONG OpenParentDir(struct FileData *fd)
  688. {
  689.   ULONG g;
  690.   UBYTE name[300];
  691.  
  692.   if((g = fd->fd_SaveDirL))
  693.   {
  694.     NameFromLock(g, name, 300);
  695.     fd->fd_SaveDirL = ParentDir(g);
  696.     UnLock(g);
  697.  
  698.     DeleteFile(name);
  699.   }
  700.   else
  701.     return -1;
  702.  
  703.   return fd->fd_SaveDirL;
  704. }
  705.  
  706. /* Open a new subdirectory for SAVE option */
  707. ULONG OpenNewDir(struct FileData *fd, STRPTR name)
  708. {
  709.   ULONG g;
  710.  
  711.   if(fd->fd_SaveDirL)
  712.   {
  713.     g = CurrentDir(fd->fd_SaveDirL);
  714.     if(!(fd->fd_SaveDirL = Lock(name, SHARED_LOCK)))
  715.       if((fd->fd_SaveDirL = CreateDir(name)))
  716.         ChangeMode(CHANGE_LOCK, fd->fd_SaveDirL, SHARED_LOCK);
  717.     UnLock(CurrentDir(g));
  718.   }
  719.   else
  720.     return -1;
  721.  
  722.   return fd->fd_SaveDirL;
  723. }
  724.  
  725. void DoMount(ULONG deep, ULONG hd)
  726. {
  727.   BPTR fh, infh;
  728.   UBYTE buf[50], buf2[60];
  729.  
  730.   sprintf(buf, "T:CheckMountList_%08lx_%03ld", FindTask(0), deep);
  731.  
  732.   if((fh = Open(buf, MODE_NEWFILE)))
  733.   {
  734.     FPrintf(fh,
  735.     "R%lc%ld:\n"
  736.     "\tDevice\t\t= ramdrive.device\n"
  737.     "\tUnit\t\t= %3ld\n"
  738.     "\tSurfaces\t=   2\n"
  739.     "\tBlocksPerTrack\t=  %ld\n"
  740.     "\tReserved\t=   2\n"
  741.     "\tInterleave\t=   0\n"
  742.     "\tLowCyl\t\t=   0\n"
  743.     "\tHighCyl\t\t=  79\n"
  744.     "\tBootPri\t\t= -10\n"
  745.     "\tBuffers\t\t=   5\n"
  746.     "\tBufMemType\t=   1\n#\n", hd ? 'H' : 'D', deep, (hd ? 50 : 10) + deep,
  747.     hd ? 22 : 11);
  748.     Close(fh);
  749.  
  750.     sprintf(buf2, "Mount R%lc%ld: FROM %s", hd ? 'H' : 'D', deep, buf);
  751.     /* I could do this myself, but I don't know, if it is the correct
  752.        method, so I use Mount command. */
  753.     if((infh = Open("NIL:", MODE_OLDFILE)))
  754.     {
  755.       if((fh = Open("NIL:", MODE_NEWFILE)))
  756.       {
  757.         SystemTags(buf2, SYS_Input, infh, SYS_Output, fh, TAG_DONE);
  758.         Close(fh);
  759.       }
  760.       Close(infh);
  761.     }
  762.     DeleteFile(buf);
  763.   }
  764. }
  765.  
  766. /* Try to get RDx: disk and initialize it. */
  767. BPTR GetRad(struct FileData *fd, STRPTR rname)
  768. {
  769.   UBYTE name[20];
  770.  
  771.   sprintf(name, NAME "%03ld", fd->fd_ArchiveDepth);
  772.  
  773.   if(Inhibit(rname, 1))
  774.   {
  775.     Format(rname, name, ID_DOS_DISK);
  776.     Inhibit(rname, 0);
  777.     return Lock(rname, SHARED_LOCK);
  778.   }
  779.   else
  780.   {
  781.     LONG i, m = 0;
  782.     UBYTE name2[20];
  783.     struct DosList *dosl;
  784.     if((dosl = LockDosList(LDF_DEVICES|LDF_READ)))
  785.     {
  786.       i = strlen(rname);
  787.       name2[--i] = 0;
  788.       while(i--)
  789.         name2[i] = rname[i];
  790.       dosl = FindDosEntry(dosl, name2, LDF_DEVICES);
  791.       UnLockDosList(LDF_DEVICES|LDF_READ);
  792.       if(!dosl && (fd->fd_Flags & CHECKXFLAG_AUTOMOUNT))
  793.       {
  794.     DoMount(fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
  795.     fd->fd_HDDepth : fd->fd_DDDepth, fd->fd_Flags &
  796.     CHECKXFLAG_HIGHDENSITY);
  797.         m = 1;
  798.       }
  799.       if(dosl || m)
  800.       {
  801.         for(i = 0; i < 50; ++i)
  802.         {
  803.           if(Inhibit(rname, 1))
  804.           {
  805.             Format(rname, name, ID_DOS_DISK);
  806.             Inhibit(rname, 0);
  807.             return Lock(rname, SHARED_LOCK);
  808.           }
  809.           Delay(10);
  810.         }
  811.         /* clear flag if mount failed */
  812.         if(m)
  813.           fd->fd_Flags &= ~CHECKXFLAG_AUTOMOUNT;
  814.       }
  815.     }
  816.   }
  817.  
  818.   return 0;
  819. }
  820.  
  821. LONG DoGetVirus(struct FileData *fd, APTR buffer, ULONG buflength)
  822. {
  823.   if(!buflength) /* restarted with empty file */
  824.     return CHKXERR_EMPTY;
  825.  
  826.   if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
  827.   {
  828.     APTR mem;
  829.       
  830.     if((mem = AllocMem(buflength, MEMF_ANY)))
  831.     {
  832.       struct xvsFileInfo *fi;
  833.       if((fi = (struct xvsFileInfo *) xvsAllocObject(XVSOBJ_FILEINFO)))
  834.       {
  835.         ULONG i;
  836.     /* xvs may modify the buffer! */
  837.         CopyMem(buffer, mem, buflength);
  838.         fi->xvsfi_File = mem;
  839.         fi->xvsfi_FileLen = buflength;
  840.         i = xvsCheckFile(fi);
  841.         if(i == XVSFT_DATAVIRUS)
  842.         {
  843.        PrintCHKXTxt(fd, "Data-Virus '%s'", fi->xvsfi_Name);
  844.        ++fd->fd_NumVirus;
  845.      }
  846.         else if(i == XVSFT_FILEVIRUS)
  847.         {
  848.        PrintCHKXTxt(fd, "File-Virus '%s'", fi->xvsfi_Name);
  849.        ++fd->fd_NumVirus;
  850.      }
  851.         else if(i == XVSFT_LINKVIRUS)
  852.         {
  853.        PrintCHKXTxt(fd, "Link-Virus '%s'", fi->xvsfi_Name);
  854.        ++fd->fd_NumVirus;
  855.      }
  856.         xvsFreeObject(fi);
  857.       }
  858.       else
  859.         PrintCHKXErr(fd, CHKXERR_NOVIRUS);
  860.       FreeMem(mem, buflength);
  861.     }
  862.     else
  863.       PrintCHKXErr(fd, CHKXERR_NOVIRUS);
  864.   }
  865.  
  866.   return DoFileUnArchive(fd, buffer, buflength);
  867. }
  868.  
  869. LONG CheckBoot(struct FileData *fd, STRPTR drivename)
  870. {
  871.   LONG err = CHKXERR_NOBOOTVIRUS;
  872.  
  873.   if(fd->fd_Flags & CHECKXFLAG_XVSLIB)
  874.   {
  875.     struct DosList *dsl;
  876.     if((dsl = LockDosList(LDF_DEVICES|LDF_READ)))
  877.     {
  878.       if((dsl = FindDosEntry(dsl, drivename, LDF_DEVICES)))
  879.       {
  880.       struct FileSysStartupMsg *fssm;
  881.  
  882.         fssm = (struct FileSysStartupMsg *) BADDR(dsl->dol_misc.dol_handler.dol_Startup);
  883.         if((LONG) fssm > 200)
  884.         {
  885.           struct DosEnvec *denv;
  886.           denv = ((struct DosEnvec *) BADDR(fssm->fssm_Environ));
  887.  
  888.           /* test if the entry is a correct fssm -> check for valid data */
  889.           if(denv && denv->de_TableSize < 64 && !(denv->de_SizeBlock &
  890.           0x127) && (denv->de_LowCyl <= denv->de_HighCyl))
  891.           {
  892.         struct MsgPort *mp;
  893.  
  894.         if((mp = CreateMsgPort()))
  895.         {
  896.               struct IOStdReq *req;
  897.  
  898.           if((req = (struct IOStdReq *) CreateIORequest(mp, sizeof(struct IOStdReq))))
  899.           {
  900.                 if(!OpenDevice(((STRPTR)(fssm->fssm_Device<<2))+1, fssm->fssm_Unit, (struct IORequest *)req, 0))
  901.                 {
  902.               APTR mem;
  903.       
  904.               if((mem = AllocMem(1024, MEMF_ANY)))
  905.               {
  906.               req->io_Command = CMD_READ;
  907.             req->io_Length = 1024;
  908.             req->io_Data = mem;
  909.          /* req->io_Offset = 0 */;
  910.               if(!DoIO((struct IORequest *)req))
  911.               {
  912.               struct xvsBootInfo *bi;
  913.                     if((bi = (struct xvsBootInfo *) xvsAllocObject(XVSOBJ_BOOTINFO)))
  914.                     {
  915.                 bi->xvsbi_Bootblock = mem;
  916.             err = 0;
  917.                 if(xvsCheckBootblock(bi) == XVSBT_VIRUS)
  918.                 {
  919.               PrintCHKXTxt(fd, "Boot-Virus '%s'", bi->xvsbi_Name);
  920.               ++fd->fd_NumVirus;
  921.              }
  922.                 xvsFreeObject(bi);
  923.                     }
  924.                   }
  925.                   FreeMem(mem, 1024);
  926.                 }
  927.               CloseDevice((struct IORequest *) req);
  928.             }
  929.                 DeleteIORequest(req);
  930.               }
  931.               DeleteMsgPort(mp);
  932.             }
  933.           }
  934.         }
  935.       }
  936.       UnLockDosList(LDF_DEVICES|LDF_READ);
  937.     }
  938.   }
  939.   else
  940.     err = 0;
  941.  
  942.   return err;
  943. }
  944.  
  945. /* Tests if a file is an archive. When yes, the archive is unarchived and
  946.    DoDirectoryScan is called for the result files. Else DoFileUnLink is
  947.    called.
  948. */
  949. LONG DoFileUnArchive(struct FileData *fd, APTR buffer, ULONG buflength)
  950. {
  951.   LONG err = 0;
  952.  
  953.   if(fd->fd_Flags & CHECKXFLAG_XADLIB)
  954.   {
  955.     struct xadArchiveInfo *ai;
  956.  
  957.     if((ai = (struct xadArchiveInfo *) xadAllocObject(XADOBJ_ARCHIVEINFO, 0)))
  958.     {
  959.       if(!xadGetInfo(ai, XAD_INMEMORY, buffer, XAD_INSIZE, buflength,
  960.       TAG_DONE))
  961.       {
  962.     STRPTR arcname;
  963.     
  964.     arcname = fd->fd_Name;
  965.  
  966.         if(ai->xai_Flags & XADAIF_FILECORRUPT)
  967.         {
  968.           ++fd->fd_CorruptedArchives;
  969.           PrintCHKXTxt(fd, "%s (ARCHIVE, CORRUPTED)", ai->xai_Client->xc_ArchiverName);
  970.         }
  971.         else
  972.           PrintCHKXTxt(fd, "%s (ARCHIVE)", ai->xai_Client->xc_ArchiverName);
  973.         
  974.         if(!(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo ||
  975.         !(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo))
  976.           err = DoFileUnLink(fd, buffer, buflength);
  977.         else if(!OpenNewDir(fd, FilePart(fd->fd_Name)))
  978.       err = CHKXERR_OPENERR;
  979.     else
  980.     {
  981.       if(!(fd->fd_Flags & CHECKXFLAG_NOUNARCHIVE) && ai->xai_FileInfo)
  982.       {
  983.         struct xadFileInfo *fi;
  984.         fi = ai->xai_FileInfo;
  985.         while(!CTRL_C && fi)
  986.         {
  987.           APTR dest;
  988.           
  989.           if(!(fi->xfi_Flags & (XADFIF_DIRECTORY|XADFIF_LINK)))
  990.           {
  991.                 ULONG flags;
  992.  
  993.                 flags = fd->fd_Flags;
  994.                 fd->fd_Flags &= ~(CHECKXFLAG_NAMEPRINTED|CHECKXFLAG_STRIPNAME);
  995.                 fd->fd_Flags |= CHECKXFLAG_FILEARCHIVED;
  996.                 fd->fd_Name = fi->xfi_FileName;
  997.                 fd->fd_RecurseDepth++;
  998.                 fd->fd_ArchiveDepth++;
  999.                 if(!fi->xfi_Size)
  1000.                   err = CHKXERR_EMPTY;
  1001.             else if((dest = AllocMem(fi->xfi_Size, MEMF_PUBLIC)))
  1002.             {
  1003.               if(!(err = AddCrunchMemList(fd, dest, fi->xfi_Size)))
  1004.               {
  1005.                     if((err = xadFileUnArc(ai, XAD_OUTMEMORY, dest, XAD_OUTSIZE,
  1006.                     fi->xfi_Size, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE)))
  1007.                       err += XADERR_OFFSET;
  1008.                     else
  1009.                     {
  1010.                       if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  1011.                       ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && fi->xfi_Size > 4
  1012.                       && *((ULONG *)dest) == HUNK_HEADER))
  1013.                         PrintCHKXFile(fd);
  1014.                       err = DoGetVirus(fd, dest, fi->xfi_Size);
  1015.                     }
  1016.                     FreeCrunchMemList(fd, dest);
  1017.                   }
  1018.                   else
  1019.                     FreeMem(dest, fi->xfi_Size);
  1020.             }
  1021.             else
  1022.               err = CHKXERR_NOMEMORY;
  1023.  
  1024.             if(err)
  1025.             {
  1026.               PrintCHKXErr(fd, err);
  1027.               err = 0;
  1028.             }
  1029.                 --fd->fd_RecurseDepth;
  1030.                 --fd->fd_ArchiveDepth;
  1031.                 fd->fd_Flags = flags;
  1032.           }
  1033.           fi = fi->xfi_Next;
  1034.         }
  1035.       }
  1036.       if(!(fd->fd_Flags & CHECKXFLAG_NOUNTRACK) && ai->xai_DiskInfo)
  1037.       {
  1038.         struct DiskInfoData {
  1039.           UBYTE name[10];
  1040.           UBYTE buf[50];
  1041.           BPTR destdir;
  1042.           ULONG geom;
  1043.         } *d;
  1044.  
  1045.         /* reduce stacksize, as we have a recursive program */
  1046.         if((d = (struct DiskInfoData *) AllocMem(sizeof(struct DiskInfoData), MEMF_PUBLIC)))
  1047.         {
  1048.               ULONG flags;
  1049.           struct xadDiskInfo *di;
  1050.           di = ai->xai_DiskInfo;
  1051.  
  1052.               flags = fd->fd_Flags;
  1053.           while(!CTRL_C && di)
  1054.           {
  1055.             if(di->xdi_SectorSize != 512 || (di->xdi_TrackSectors != 11 &&
  1056.             di->xdi_TrackSectors != 22) || (!(di->xdi_Flags & XADDIF_NOHEADS) &&
  1057.             di->xdi_Heads != 2) || (!(di->xdi_Flags & XADDIF_NOCYLINDERS) &&
  1058.             di->xdi_Cylinders != 80))
  1059.             {
  1060.               sprintf(d->buf, "-disk image %ld (unsupported geometry)", di->xdi_EntryNumber);
  1061.               d->geom = 1;
  1062.             }
  1063.             else
  1064.             {
  1065.               d->geom = 0;
  1066.               if(di->xdi_TrackSectors == 11)
  1067.                     sprintf(d->name, "RD%ld:", fd->fd_DDDepth);
  1068.               else
  1069.               {
  1070.                 fd->fd_Flags |= CHECKXFLAG_HIGHDENSITY;
  1071.                     sprintf(d->name, "RH%ld:", fd->fd_HDDepth);
  1072.                   }
  1073.  
  1074.           if(!(di->xdi_Flags & (XADDIF_NOHIGHCYL|XADDIF_NOLOWCYL)) &&
  1075.           (di->xdi_LowCyl || di->xdi_HighCyl != 79))
  1076.                 sprintf(d->buf, "-disk image %ld (%s, %ld to %ld)",
  1077.                 di->xdi_EntryNumber, fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
  1078.                 "HD" : "DD", di->xdi_LowCyl, di->xdi_HighCyl);
  1079.               else
  1080.                 sprintf(d->buf, "-disk image %ld (%s)",
  1081.                 di->xdi_EntryNumber, fd->fd_Flags & CHECKXFLAG_HIGHDENSITY ?
  1082.                 "HD" : "DD");
  1083.             }
  1084.           
  1085.                 fd->fd_Flags &= ~(CHECKXFLAG_NAMEPRINTED|CHECKXFLAG_STRIPNAME);
  1086.             fd->fd_Name = d->buf;
  1087.                 PrintCHKXFile(fd);
  1088.  
  1089.             if(di->xdi_TextInfo)
  1090.             {
  1091.               struct xadTextInfo *ti;
  1092.               ULONG flags, i = 1;
  1093.  
  1094.           for(ti = di->xdi_TextInfo; ti; ti = ti->xti_Next)
  1095.           {
  1096.             if(ti->xti_Size && ti->xti_Text)
  1097.             {
  1098.                       flags = fd->fd_Flags;
  1099.                       fd->fd_Flags &= ~CHECKXFLAG_NAMEPRINTED;
  1100.                       fd->fd_Flags |= CHECKXFLAG_NOFREEMEM|CHECKXFLAG_DISKARCHIVED;
  1101.                       fd->fd_RecurseDepth++;
  1102.                       sprintf(d->buf, "--infotext %ld (size %ld)", i, ti->xti_Size);
  1103.                       if((fd->fd_Flags & CHECKXFLAG_PRINTALL) ||
  1104.                       ((fd->fd_Flags & CHECKXFLAG_PRINTEXEC) && ti->xti_Size > 4
  1105.                       && *((ULONG *)(ti->xti_Text)) == HUNK_HEADER))
  1106.                         PrintCHKXFile(fd);
  1107.                       PrintCHKXErr(fd, DoGetVirus(fd, ti->xti_Text, ti->xti_Size));
  1108.                       --fd->fd_RecurseDepth;
  1109.                       fd->fd_Flags = flags;
  1110.                     }
  1111.                     ++i;
  1112.                   }
  1113.             }
  1114.  
  1115.             if(!d->geom)
  1116.             {
  1117.               if((di->xdi_LowCyl == 0 && di->xdi_HighCyl == 79) ||
  1118.               !(fd->fd_Flags & CHECKXFLAG_NOTRACKCUT) ||
  1119.               (di->xdi_Flags & XADDIF_NOCYLINDERS))
  1120.           {
  1121.                     if((d->destdir = GetRad(fd, d->name)))
  1122.                     {
  1123.               struct xadDeviceInfo *dvi;
  1124.  
  1125.                   UnLock(d->destdir);
  1126.  
  1127.                   if((dvi = (struct xadDeviceInfo *)
  1128.                   xadAllocObjectA(XADOBJ_DEVICEINFO, 0)))
  1129.                   {
  1130.                     d->name[strlen(d->name)-1] = 0;
  1131.                     dvi->xdi_DOSName = d->name;
  1132.                     if(!(err = xadDiskUnArc(ai, XAD_OUTDEVICE, dvi,
  1133.                 XAD_ENTRYNUMBER, di->xdi_EntryNumber, XAD_VERIFY,
  1134.                 TRUE, TAG_DONE)) && !di->xdi_LowCyl)
  1135.                   PrintCHKXErr(fd, CheckBoot(fd, d->name));
  1136.                     xadFreeObjectA(dvi, 0);
  1137.                     d->name[strlen(d->name)] = ':';
  1138.                   }
  1139.                   else
  1140.                     err = CHKXERR_NOMEMORY;
  1141.  
  1142.               if(err)
  1143.               {
  1144.                 PrintCHKXErr(fd, XADERR_OFFSET+err); err = 0;
  1145.               }
  1146.               else if(!(d->destdir = Lock(d->name, SHARED_LOCK)))
  1147.                         PrintCHKXErr(fd, CHKXERR_NODOS);
  1148.                       else
  1149.                       {
  1150.                     struct FileData fdp;
  1151.  
  1152.                     CopyMem(fd, &fdp, sizeof(struct FileData));
  1153.                     fdp.fd_Flags = (fdp.fd_Flags&CHKXCALLFLAGS)|CHECKXFLAG_ALL|CHECKXFLAG_STRIPNAME;
  1154.                     fdp.fd_MemList = 0;
  1155.                 fdp.fd_ArchiveDepth++;
  1156.                 fdp.fd_RecurseDepth++;
  1157.                     if(fd->fd_Flags & CHECKXFLAG_HIGHDENSITY)
  1158.                       ++fdp.fd_HDDepth;
  1159.                     else
  1160.                       ++fdp.fd_DDDepth;
  1161.  
  1162.                       PrintCHKXErr(fd, DoDirectoryScan(d->name, 0, &fdp));
  1163.                       fd->fd_SaveDirL   = fdp.fd_SaveDirL;
  1164.                       fd->fd_NumVirus   = fdp.fd_NumVirus;
  1165.                   fd->fd_CHKXErrors = fdp.fd_CHKXErrors;
  1166.                   fd->fd_XFDErrors  = fdp.fd_XFDErrors;
  1167.                   fd->fd_XADErrors  = fdp.fd_XADErrors;
  1168.                   fd->fd_CorruptedArchives = fdp.fd_CorruptedArchives;
  1169.                       UnLock(d->destdir);
  1170.                       }
  1171.                     }
  1172.                     else
  1173.                       PrintCHKXErr(fd, CHKXERR_NORAD);
  1174.               }
  1175.             }
  1176.             fd->fd_Flags &= ~CHECKXFLAG_HIGHDENSITY;
  1177.             di = di->xdi_Next;
  1178.           } /* while */
  1179.           fd->fd_Flags = flags;
  1180.           FreeMem(d, sizeof(struct DiskInfoData));
  1181.         } /* AllocMem DiskInfoData */
  1182.         else
  1183.           err = CHKXERR_NOMEMORY;
  1184.       } /* is there is disk entry? */
  1185.           if(!OpenParentDir(fd))
  1186.             err = CHKXERR_OPENDIR;
  1187.     }
  1188.     
  1189.     fd->fd_Name = arcname;
  1190.     xadFreeInfo(ai);
  1191.       }
  1192.       else
  1193.         err = DoFileUnLink(fd, buffer, buflength);
  1194.  
  1195.       xadFreeObjectA(ai, 0);
  1196.     }
  1197.     else
  1198.       err = CHKXERR_NOMEMORY;
  1199.   }
  1200.   else
  1201.     err = DoFileUnLink(fd, buffer, buflength);
  1202.  
  1203.   return err;
  1204. }
  1205.  
  1206. /* Tries to unlink a file. When the file was linked, we call DoGetVirus
  1207.    for the two parts to check if they may be archives, else we call
  1208.    DoFileUnCrunch.
  1209. */
  1210. LONG DoFileUnLink(struct FileData *fd, APTR buffer, ULONG buflength)
  1211. {
  1212.   LONG ret = CHKXERR_NOMEMORY;
  1213.   struct xfdLinkerInfo *xli;
  1214.  
  1215.   if((xli = (struct xfdLinkerInfo *) xfdAllocObject(XFDOBJ_LINKERINFO)))
  1216.   {
  1217.     xli->xfdli_Buffer = buffer;
  1218.     xli->xfdli_BufLen = buflength;
  1219.     if(xfdRecogLinker(xli))
  1220.     {
  1221.       PrintCHKXTxt(fd, xli->xfdli_LinkerName);
  1222.       if(fd->fd_Flags & CHECKXFLAG_NOUNLINK)
  1223.         ret = DoFileUnCrunch(fd, buffer, buflength);
  1224.       else if(xfdUnlink(xli))
  1225.       {
  1226.         ULONG flags;
  1227.     fd->fd_Flags |= CHECKXFLAG_LINKED;
  1228.         ++fd->fd_RecurseDepth;
  1229.         ++fd->fd_LinkNum;
  1230.     flags = fd->fd_Flags;
  1231.     fd->fd_Flags |= CHECKXFLAG_NOFREEMEM;
  1232.         PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save1,
  1233.         xli->xfdli_SaveLen1));
  1234.         fd->fd_Flags = flags; /* CHECKXFLAG_NOFREEMEM is cleared */
  1235.         PrintCHKXErr(fd, DoGetVirus(fd, xli->xfdli_Save2,
  1236.         xli->xfdli_SaveLen2));
  1237.         ret = 0;
  1238.         --fd->fd_RecurseDepth;
  1239.       }
  1240.       else
  1241.         ret = XFDERR_OFFSET + xli->xfdli_Error;
  1242.     }
  1243.     else
  1244.       ret = DoFileUnCrunch(fd, buffer, buflength);
  1245.  
  1246.     xfdFreeObject(xli);
  1247.   }
  1248.   return ret;
  1249. }
  1250.  
  1251. /* Tries to decrunch a file. When it is crunched, we decrunch it and call
  1252.    DoGetVirus to start the loop again. Else we call unstripping.
  1253. */
  1254. LONG DoFileUnCrunch(struct FileData *fd, APTR buffer, ULONG buflength)
  1255. {
  1256.   LONG ret = CHKXERR_NOMEMORY;
  1257.   struct xfdBufferInfo *xbi;
  1258.  
  1259.   if((xbi = (struct xfdBufferInfo *) xfdAllocObject(XFDOBJ_BUFFERINFO)))
  1260.   {
  1261.     xbi->xfdbi_SourceBuffer = buffer;
  1262.     xbi->xfdbi_SourceBufLen = buflength;
  1263.     xbi->xfdbi_Flags = XFDFF_RECOGEXTERN;
  1264.     if(xfdRecogBuffer(xbi))
  1265.     {
  1266.       struct Library *xpkbase;
  1267.       STRPTR buf = 0;
  1268.       ULONG buflen = 0;
  1269.  
  1270.       PrintCHKXTxt(fd, xbi->xfdbi_PackerFlags & XFDPFF_ADDR ? "%s (ADDRESS)" :
  1271.       "%s", xbi->xfdbi_PackerName);
  1272.  
  1273.       if(fd->fd_Flags & CHECKXFLAG_ASKPWD && (xpkbase =
  1274.       OpenLibrary(XPKNAME, 4)))
  1275.       {
  1276.     ASSIGN_XPK
  1277.         if(xbi->xfdbi_PackerFlags & XFDPFF_PASSWORD)
  1278.         {
  1279.           buflen = (xbi->xfdbi_MaxSpecialLen == 0xFFFF) ? 256 :
  1280.         xbi->xfdbi_MaxSpecialLen;
  1281.           if((buf = (STRPTR) AllocMem(buflen, MEMF_ANY|MEMF_CLEAR)))
  1282.       {
  1283.             if(!XpkPassRequestTags(XPK_PasswordBuf, buf,
  1284.             XPK_PassBufSize, buflen, TAG_DONE))
  1285.           xbi->xfdbi_Special = buf;
  1286.       }
  1287.         }
  1288.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY16)
  1289.         {
  1290.       if(!XpkPassRequestTags(XPK_Key16BitPtr, &buflen, TAG_DONE))
  1291.         xbi->xfdbi_Special = &buflen;
  1292.         }
  1293.         else if(xbi->xfdbi_PackerFlags & XFDPFF_KEY32)
  1294.         {
  1295.       if(!XpkPassRequestTags(XPK_Key32BitPtr, &buflen, TAG_DONE))
  1296.             xbi->xfdbi_Special = &buflen;
  1297.         }
  1298.     CloseLibrary(xpkbase);
  1299.       }
  1300.       if(fd->fd_Flags & CHECKXFLAG_NODECRUNCH)
  1301.         ret = DoFileStrip(fd, buffer, buflength);
  1302.       else if(xfdDecrunchBuffer(xbi))
  1303.       {
  1304.         if((xbi->xfdbi_PackerFlags & XFDPFF_ADDR) &&
  1305.         !(fd->fd_Flags & CHECKXFLAG_ADDRESS))
  1306.         {
  1307.       fd->fd_Flags |= CHECKXFLAG_ADDRESS;
  1308.           PrintCHKXErr(fd, SaveUncrFile(fd, buffer, buflength));
  1309.         }
  1310.     fd->fd_Flags |= CHECKXFLAG_CRUNCHED;
  1311.         FreeCrunchMemList(fd, buffer);
  1312.         ++fd->fd_RecurseDepth;
  1313.         if(!(ret = AddCrunchMemList(fd, xbi->xfdbi_TargetBuffer,
  1314.         xbi->xfdbi_TargetBufLen)))
  1315.         {
  1316.           PrintCHKXErr(fd, DoGetVirus(fd, xbi->xfdbi_TargetBuffer,
  1317.             xbi->xfdbi_TargetBufSaveLen));
  1318.         }
  1319.         --fd->fd_RecurseDepth;
  1320.       }
  1321.       else
  1322.         ret = XFDERR_OFFSET + xbi->xfdbi_Error;
  1323.  
  1324.       if(buf)
  1325.         FreeMem(buf, buflen);
  1326.     }
  1327.     else
  1328.       ret = DoFileStrip(fd, buffer, buflength);
  1329.  
  1330.     xfdFreeObject(xbi);
  1331.   }
  1332.   return ret;
  1333. }
  1334.  
  1335. /* Tries to strip useless hunks in a file. When there are some, we remove
  1336.    them and call DoGetVirus to start the loop again. Else we finish.
  1337.    When either unlinking or uncrunching happend in before loops, we may
  1338.    save the file when there was SAVE option.
  1339. */
  1340. LONG DoFileStrip(struct FileData *fd, APTR buffer, ULONG buflength)
  1341. {
  1342.   LONG ret = 0;
  1343.   ULONG reslength = buflength;
  1344.  
  1345.   if(*((ULONG *) buffer) == 0x000003F3 && !(fd->fd_Flags &
  1346.   CHECKXFLAG_NOSTRIP))
  1347.     xfdStripHunks(buffer, buflength, &reslength,
  1348.     XFDSHF_NAME|XFDSHF_SYMBOL|XFDSHF_DEBUG);
  1349.     /* errors are not interpreted */
  1350.  
  1351.   if(buflength > reslength)
  1352.   {
  1353.     fd->fd_Flags |= CHECKXFLAG_STRIPPED;
  1354.     PrintCHKXTxt(fd, "%ld bytes stripped", buflength-reslength);
  1355.     ret = DoGetVirus(fd, buffer, reslength);
  1356.   }
  1357.   else if(!(fd->fd_Flags & CHECKXFLAG_ADDRESS))
  1358.     ret = SaveUncrFile(fd, buffer, buflength);
  1359.  
  1360.   FreeCrunchMemList(fd, buffer);
  1361.  
  1362.   return ret;
  1363. }
  1364.  
  1365. /* Print file name */
  1366. void PrintCHKXFile(struct FileData *fd)
  1367. {
  1368.   STRPTR name = fd->fd_Name;
  1369.   UBYTE i;
  1370.  
  1371.   if(fd->fd_Flags & CHECKXFLAG_STRIPNAME) /* skip that ugly RH?: or RD?: */
  1372.   {
  1373.     while(*name != ':')
  1374.       ++name;
  1375.     ++name;
  1376.   }
  1377.  
  1378.   if(fd->fd_Flags & CHECKXFLAG_DEBUG)
  1379.   {
  1380.     for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1381.       KPutC('*');
  1382.     KPrintf("%s\n", name);
  1383.   }
  1384.  
  1385.   if(fd->fd_LogFileFH)
  1386.   {
  1387.     for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1388.       FPutC(fd->fd_LogFileFH, '*');
  1389.     FPrintf(fd->fd_LogFileFH, "%s\n", name);
  1390.   }
  1391.   if(!(fd->fd_Flags & CHECKXFLAG_QUIET))
  1392.   {
  1393.     for(i = 0; i < fd->fd_ArchiveDepth; ++i)
  1394.       FPutC(Output(), '*');
  1395.     Printf("%s\n", name);
  1396.   }
  1397.   fd->fd_Flags |= CHECKXFLAG_NAMEPRINTED;
  1398. }
  1399.  
  1400. void PrintCHKXErr(struct FileData *fd, LONG err)
  1401. {
  1402.   if(err)
  1403.   {
  1404.     STRPTR txt = 0, txt2;
  1405.  
  1406.     if(err > XFDERR_OFFSET)
  1407.     {
  1408.       ++fd->fd_XFDErrors;
  1409.       txt2 = "XFD-Error %ld: %s";
  1410.       err -= XFDERR_OFFSET;
  1411.       txt = xfdGetErrorText(err);
  1412.     }
  1413.     else if(err > XADERR_OFFSET)
  1414.     {
  1415.       ++fd->fd_XADErrors;
  1416.       txt2 = "XAD-Error %ld: %s";
  1417.       err -= XADERR_OFFSET;
  1418.       txt = xadGetErrorText(err);
  1419.     }
  1420.     else if(err > CHXWARN_OFFSET)
  1421.     {
  1422.       txt2 = "CheckX-Warning %ld: %s";
  1423.       switch(err)
  1424.       {
  1425.       case CHKXWARN_NOVIRUS:    txt = "Virus-Checking disabled!";                        break;
  1426.       case CHKXWARN_XVSSELFTEST:txt = "The xvs.library is modified, maybe the system is virus infected!";    break;
  1427.       case CHKXWARN_MEMVIRUS:    txt = "Your system memory was virus infected!";                    break;
  1428.       }
  1429.       err -= CHXWARN_OFFSET;
  1430.     }
  1431.     else
  1432.     {
  1433.       ++fd->fd_CHKXErrors;
  1434.       txt2 = "CheckX-Error %ld: %s";
  1435.       switch(err)
  1436.       {
  1437.       case CHKXERR_NOMEMORY:    txt = "not enough memory";            break;
  1438.       case CHKXERR_EXAMINEERR:    txt = "examining failed";            break;
  1439.       case CHKXERR_OPENERR:    txt = "opening file failed";            break;
  1440.       case CHKXERR_READ:    txt = "reading failed";                break;
  1441.       case CHKXERR_SCANERR:    txt = "directory scan failed";            break;
  1442.       case CHKXERR_BREAK:    txt = "user break";                break;
  1443.       case CHKXERR_OPENDIR:    txt = "opening directory failed";        break;
  1444.       case CHKXERR_NORAD:    txt = "accessing ramdrive failed";        break;
  1445.       case CHKXERR_NODOS:    txt = "not an Amiga DOS disk";            break;
  1446.       case CHKXERR_RESOURCE:    txt = "needed resource not available";        break;
  1447.       case CHKXERR_NOVIRUS:    txt = "could not check for virus";        break;
  1448.       case CHKXERR_EMPTY:    txt = "file is empty";                break;
  1449.       case CHKXERR_NOBOOTVIRUS:    txt = "could not check for bootblock virus";    break;
  1450.       case CHKXERR_WRITE:    txt = "writing failed";                break;
  1451.       }
  1452.     }
  1453.  
  1454.     PrintCHKXTxt(fd, txt2, err, txt);
  1455.   }
  1456. }
  1457.  
  1458. /* Print type text */
  1459. void PrintCHKXTxt(struct FileData *fd, STRPTR txt, ...)
  1460. {
  1461.   UBYTE i;
  1462.  
  1463.   if(!(fd->fd_Flags & CHECKXFLAG_NAMEPRINTED))
  1464.     PrintCHKXFile(fd);
  1465.  
  1466.   if(fd->fd_Flags & CHECKXFLAG_DEBUG)
  1467.   {
  1468.     for(i = 0; i < fd->fd_RecurseDepth; ++i)
  1469.       KPutC(' ');
  1470.     RawDoFmt(txt, &txt+1, (void (*)()) KPutC, 0);
  1471.     KPutC('\n');
  1472.   }
  1473.  
  1474.   if(fd->fd_LogFileFH)
  1475.   {
  1476.     for(i = 0; i < fd->fd_RecurseDepth; ++i)
  1477.       FPutC(fd->fd_LogFileFH, ' ');
  1478.     VFPrintf(fd->fd_LogFileFH, txt, &txt+1);
  1479.     FPutC(fd->fd_LogFileFH, '\n');
  1480.     Flush(fd->fd_LogFileFH);
  1481.   }
  1482.  
  1483.   if(!(fd->fd_Flags & CHECKXFLAG_QUIET))
  1484.   {
  1485.     for(i = 0; i < fd->fd_RecurseDepth; ++i)
  1486.       FPutC(Output(), ' ');
  1487.     VPrintf(txt, &txt+1);
  1488.     FPutC(Output(), '\n');
  1489.   }
  1490. }
  1491.  
  1492. /* Add memory to the memory list. */
  1493. LONG AddCrunchMemList(struct FileData *fd, APTR reg, ULONG size)
  1494. {
  1495.   struct CrunchMemList *ml;
  1496.  
  1497.   if((ml = (struct CrunchMemList *) AllocMem(sizeof(struct CrunchMemList),
  1498.   MEMF_ANY)))
  1499.   {
  1500.     ml->cml_Next = fd->fd_MemList;
  1501.     ml->cml_MemoryRegion = reg;
  1502.     ml->cml_MemorySize = size;
  1503.     fd->fd_MemList = ml;
  1504.   }
  1505.   else
  1506.   {
  1507.     FreeMem(reg, size);
  1508.     return CHKXERR_NOMEMORY;
  1509.   }
  1510.   return 0;
  1511. }
  1512.  
  1513. /* Free memory from the memory list. */
  1514. void FreeCrunchMemList(struct FileData *fd, APTR reg)
  1515. {
  1516.   struct CrunchMemList mc, *ml = &mc;
  1517.  
  1518.   if(fd->fd_Flags & CHECKXFLAG_NOFREEMEM)
  1519.     return;
  1520.  
  1521.   for(mc.cml_Next = fd->fd_MemList; ml; ml = ml->cml_Next)
  1522.   {
  1523.     if(ml->cml_Next->cml_MemoryRegion == reg)
  1524.     {
  1525.       struct CrunchMemList *m;
  1526.       m = ml->cml_Next;
  1527.       ml->cml_Next = m->cml_Next;
  1528.       FreeMem(m->cml_MemoryRegion, m->cml_MemorySize);
  1529.       FreeMem(m, sizeof(struct CrunchMemList));
  1530.     }
  1531.   }
  1532.  
  1533.   fd->fd_MemList = mc.cml_Next;
  1534. }
  1535.  
  1536. /* Save file, when SAVE option and file was crunched or linked. */
  1537. LONG SaveUncrFile(struct FileData *fd, APTR buf, ULONG size)
  1538. {
  1539.   BPTR filefh, cd;
  1540.   LONG ret = 0, i = 0;
  1541.   UBYTE name[50];
  1542.   UBYTE nbuf[256];
  1543.  
  1544.   if(!(fd->fd_SaveDirL && (fd->fd_Flags & CHKXSAVEFLAGS)))
  1545.     return 0;
  1546.  
  1547.   sprintf(name, (fd->fd_LinkNum ? "%s.%ld" : "%s"), FilePart(fd->fd_Name),
  1548.   fd->fd_LinkNum++);
  1549.  
  1550.   cd = CurrentDir(fd->fd_SaveDirL);
  1551.  
  1552.   while(!ret && name[i])
  1553.   {
  1554.     for(;name[i] && name[i] != '/'; ++i)
  1555.       nbuf[i] = name[i];
  1556.     if(name[i] == '/')
  1557.     {
  1558.       nbuf[i] = 0;
  1559.       if((filefh = Lock(nbuf, SHARED_LOCK)))
  1560.         UnLock(filefh);
  1561.       else
  1562.       {
  1563.         if((filefh = CreateDir(nbuf)))
  1564.           UnLock(filefh);
  1565.         else
  1566.           ret = CHKXERR_OPENERR;
  1567.       }
  1568.       nbuf[i] = name[i];
  1569.       ++i;
  1570.     }
  1571.   }
  1572.  
  1573.   if(!ret)
  1574.   {
  1575.     if((filefh = Open(name, MODE_NEWFILE)))
  1576.     {
  1577.       if(Write(filefh, buf, size) != size)
  1578.         ret = CHKXERR_WRITE;
  1579.       Close(filefh);
  1580.     }
  1581.     else
  1582.       ret = CHKXERR_OPENERR;
  1583.   }
  1584.  
  1585.   CurrentDir(cd);
  1586.  
  1587.   return ret;
  1588. }
  1589.  
  1590.